package com.TangoGames.box2d;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.jbox2d.common.OBBViewportTransform;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;

import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.MotionEvent;

import com.TangoGames.box2d.PhysicsSimulator.Gravitys;
import com.TangoGames.panel.BasePanel;
import com.TangoGames.panel.IPanelElement;
import com.TangoGames.panel.IPanelState;

public abstract class WorldPanelState implements IPanelState {

	/**
	 * TAG
	 */
	protected static final String TAG = WorldPanelState.class.getSimpleName();

	/**
	 * World to Sreen scale
	 */
	final public float WSCALE = 10.0F;

	/**
	 * 
	 */
	protected ArrayList<IPanelElement> childrenElements = new ArrayList<IPanelElement>();

	/**
	 * 
	 */
	private PhysicsSimulator simulator;

	/**
	 * 
	 * @return
	 */
	public PhysicsSimulator getSimulator() {
		return simulator;
	}

	/**
	 * 
	 */
	protected boolean isInit = false;

	/**
	 * 
	 */
	protected OBBViewportTransform viewportTransform;

	/**
	 * 
	 * @return
	 */
	public OBBViewportTransform getViewportTransform() {
		return viewportTransform;
	}

	/**
	 * 
	 */
	protected BasePanel basepanel;

	/**
	 * 
	 */
	private boolean drawActors = true;

	/**
	 * 
	 * @return
	 */
	public boolean isDrawActors() {
		return drawActors;
	}

	/**
	 * 
	 * @param drawActors
	 */
	public void setDrawActors(boolean drawActors) {
		this.drawActors = drawActors;
	}

	/**
	 * Constructor
	 */
	public WorldPanelState() {
		viewportTransform = new OBBViewportTransform();
	}

	@Override
	public void Init(BasePanel basepanel) {

		this.basepanel = basepanel;

		// viewportTransform.setCenter(, ));

		isInit = true;

		simulator = new PhysicsSimulator();

		simulator.createWorld(Gravitys.EARTH.getVetorialGravity());

		simulator.setStepTimeFator(WSCALE);

		InitializeWorld(simulator);

	}

	/**
	 * Create a initial bodys
	 */
	protected abstract void InitializeWorld(PhysicsSimulator simulator);

	@Override
	public void Start() {

		// Log.d(TAG, "Start");

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		// Log.d(TAG, "onTouchEvent");

		return false;
	}

	@Override
	final public void Draw(Canvas canvas) {
		//
		SetupViewportTransform(0, 0, 0, canvas.getHeight(), WSCALE, true);
		//
		simulator.Draw(canvas);
		// abstract
		Draw(simulator, canvas);

	}

	/**
	 * Setup values do viewportTransfom
	 * 
	 * @param centerX
	 * @param centerY
	 * @param offsetX
	 * @param offsetY
	 * @param scale
	 * @param flipY
	 */
	protected void SetupViewportTransform(float centerX, float centerY,
			float offsetX, float offsetY, float scale, boolean flipY) {
		//
		viewportTransform.setExtents(offsetX, offsetY);
		//
		viewportTransform.setCamera(centerX, centerY, scale);
		//
		viewportTransform.setYFlip(flipY);
	}

	/**
	 * Implements your draw
	 * 
	 * @param simulator
	 * @param canvas
	 */
	abstract public void Draw(PhysicsSimulator simulator, Canvas canvas);

	@Override
	final public void Update(long gameTime) {
		//remove actors
		List<ActorToRemove> listOfRemove = new ArrayList<ActorToRemove>(); 
		removeAtorsChildElements( this.getChildrenElements(), listOfRemove);
		
		for(ActorToRemove actor : listOfRemove) {
			actor.removeItselfFromCollection();
		}
		
		//
		simulator.Update(gameTime);
		//
		// abstract method
		Update(simulator, gameTime);
	}

	class ActorToRemove {
		private BaseActor actor;
		private Collection<IPanelElement> collection;
		
		public ActorToRemove(BaseActor actor, Collection<IPanelElement> collection) {
			this.actor = actor;
			this.collection = collection;
		}
		
		public void removeItselfFromCollection() {
			getCollection().remove(getActor());
		}
		
		public BaseActor getActor() {
			return actor;
		}
		public void setActor(BaseActor actor) {
			this.actor = actor;
		}
		public Collection<IPanelElement> getCollection() {
			return collection;
		}
		public void setCollection(Collection<IPanelElement> collection) {
			this.collection = collection;
		}
	}
	
	/**
	 * Call all of children updates
	 * 
	 * @param childrenElements
	 */
	private void removeAtorsChildElements(
			Collection<IPanelElement> childrenElements,
			List<ActorToRemove> listOfRemove) {
		if (!childrenElements.isEmpty()) {
			for (IPanelElement entry : childrenElements) {
				if (entry instanceof BaseActor && ((BaseActor) entry).isMarkToRemove()) {
					listOfRemove.add(new ActorToRemove((BaseActor) entry, childrenElements));
				}
				if (entry.getChildrenElements() != null) {
					removeAtorsChildElements(entry.getChildrenElements(), listOfRemove);
				}
			}
		}
	}

	/**
	 * Implements your update
	 * 
	 * @param simulator
	 * @param gameTime
	 */
	abstract public void Update(PhysicsSimulator simulator, long gameTime);

	@Override
	public BasePanel getBasePanel() {
		// TODO Auto-generated method stub
		return basepanel;
	}

	@Override
	public void setBasePanel(BasePanel basepanel) {
		this.basepanel = basepanel;
	}

	@Override
	public void Resume() {
		// TODO Auto-generated method stub

	}

	@Override
	public void Pause() {
		// TODO Auto-generated method stub

	}

	@Override
	public void Destroy() {
		viewportTransform = null;
		if (isInit) {
			simulator.Destroy();
			simulator = null;
		}

	}

	@Override
	public boolean isAlreadyIinitialized() {
		return isInit;
	}

	/**
	 * creator a Retangle Actor
	 * 
	 * @param actor
	 * @param rect
	 * @return
	 */
	public Body createActor(BaseActor actor, Rect rect) {
		Vec2 pos = new Vec2(rect.left, rect.top);
		// SetupViewportTransform(0,0,0,this.basepanel.getHeight(),WSCALE,true);
		Vec2 wordpos = new Vec2();
		viewportTransform.getScreenToWorld(pos, wordpos);
		return simulator.createRectangle(wordpos.x, wordpos.y,
				(float) (rect.width() / WSCALE),
				(float) (rect.height() / WSCALE),
				PhysicsSimulator.Materials.STANDARD, actor);
	}

	/**
	 * Create a Circle Actor
	 * 
	 * @param actor
	 * @param center
	 * @param radius
	 * @return
	 */
	public Body createActor(BaseActor actor, Point center, int radius) {
		Vec2 pos = new Vec2(center.x, center.y);
		Vec2 wordpos = new Vec2();
		viewportTransform.getScreenToWorld(pos, wordpos);
		return simulator.createCircle(wordpos.x, wordpos.y,
				(float) (radius / WSCALE), PhysicsSimulator.Materials.STANDARD,
				actor);
	}

	@Override
	public Collection<IPanelElement> getChildrenElements() {
		return childrenElements;
	}

	@Override
	public IPanelElement getParentElement() {
		// TODO Auto-generated method stub
		return null;
	}

}
